package cn.wolfcode.web.controller;

import cn.wolfcode.common.constants.CommonConstants;
import cn.wolfcode.common.domain.UserInfo;
import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.common.web.anno.RequireLogin;
import cn.wolfcode.domain.OrderInfo;
import cn.wolfcode.domain.SeckillProductVo;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.mq.OrderMessage;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.DateUtil;
import cn.wolfcode.util.UserUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;


@RestController
@RequestMapping("/order")
@Slf4j
public class OrderInfoController {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IOrderInfoService orderInfoService;

    // 本地标识, 减少访问redis的次数 <seckillId, Boolean>: Boolean 为 true 即无库存
    public static ConcurrentHashMap<Long, Boolean> stockCountMap = new ConcurrentHashMap<>();


    /**
     * 秒杀功能
     * @param seckillId
     * @return      返回 t_order_info 表的 orderNo, 前端拿来直接跳转
     * @RequireLogin: 自定义注解, 本服务添加了对应实现的拦截器, 根据 token 判断是否登录, 如果未登录, 则返回登录超时
     */
    // 1. 判断是否登录状态
    @RequireLogin
    @PostMapping("/doSeckill")
    public Result<String> doSeckill(Long seckillId, int time, HttpServletRequest request) {
        SeckillProductVo seckillProductVo = seckillProductService.find(time, seckillId);
        String token = request.getHeader(CommonConstants.TOKEN_NAME);
        UserInfo userInfo = UserUtil.getUser(redisTemplate, token);     // 好像封装了, 但是就俩条语句...

        // 2. 参数校验
        if (StringUtils.isEmpty(String.valueOf(seckillId)) || StringUtils.isEmpty(String.valueOf(time))) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }

        // 利用 本地标识, 减少访问redis的次数
        Boolean flag = stockCountMap.get(seckillId);
        if (flag != null && flag) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        // 3. 判断是否秒杀活动时间范围内
        if (!DateUtil.isLegalTime(seckillProductVo.getStartDate(), time)){
            throw new BusinessException(SeckillCodeMsg.SECKILL_NOT_START);
        };

        // 4. 判断库存是否足够
        if (seckillProductVo.getStockCount() <= 0)
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);

        // 5. 判断用户是否重复下单 (看redis中是否有相关记录: set :  key=pre:time, value=phone:seckillId)
        if (redisTemplate.opsForSet().isMember(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(String.valueOf(time)), userInfo.getPhone() + ":" + seckillId))
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);

        // 利用redis中的预库存, 控制访问 mysql的人数
        Long count = redisTemplate.opsForHash().increment(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(String.valueOf(time)), String.valueOf(seckillId), -1);
        if (count < 0) {
            stockCountMap.put(seckillId, true);
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

//        // 6. 秒杀逻辑处理, 返回 order 订单的编号 (下面改用  MQ)
//        String orderNo = orderInfoService.doSeckill(seckillProductVo, userInfo);

        // 6. 将数据封装为  Message, 发送到MQ, 逻辑交给其他服务处理
        OrderMessage message = new OrderMessage(seckillProductVo, userInfo, token);
        rocketMQTemplate.sendOneWay(MQConstant.ORDER_PEDDING_TOPIC, message);
        return Result.success("正在抢购中, 请稍后再试");
    }

    @GetMapping("/find")
    public Result<OrderInfo> find(String orderNo, HttpServletRequest request) {
        if (StringUtils.isEmpty(orderNo)) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }

        OrderInfo orderInfo = orderInfoService.find(orderNo);

        // 不存在的订单编号
        if (orderInfo == null)
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);

        String token = request.getHeader(CommonConstants.TOKEN_NAME);
        UserInfo userInfo = UserUtil.getUser(redisTemplate, token);

        // 订单编号对应的用户id和当前用户id不一致
        if (!orderInfo.getUserId().equals(userInfo.getPhone()))
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);

        return Result.success(orderInfo);
    }
}
